﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;

namespace Nate_sRoguelikeGame
{
    enum RoomSize
    {
        Small = 0,
        Medium,
        Large
    }
    class Room
    {
        public Rectangle OuterPerimeter { get; private set; }

        // Returns the inside of the room
        public Rectangle InnerPerimeter
        {
            get
            {
                var innerPerimeter = Rectangle.Inflate(OuterPerimeter, -1, -1);
                //innerPerimeter.Offset(1, 1);
                
                return innerPerimeter;
            }
        }

        public List<Room> _rooms;
        private Rectangle _levelDimensions;
        private GameArchitecture _wallType;
        private string _name;
        private Level _level;
        public Room(Level level, string name, GameArchitecture wallType, List<Room> rooms, Rectangle levelDimensions)
        {
            _name = name;
            _level = level;
            OuterPerimeter = new Rectangle(0, 0, 0, 0);
            _rooms = rooms;
            _levelDimensions = levelDimensions;
            _wallType = wallType;
        }

        public void AddToMap(MapBlock[][] map)
        {
            int l = map.Length;

            File.AppendAllText("map.txt",
                               String.Format("Room {0}: Position: ({1}, {2}) Size: ({3}, {4})\r\n",
                                             new object[]
                                                 {
                                                     _name,
                                                     OuterPerimeter.X, 
                                                     OuterPerimeter.Y,
                                                     OuterPerimeter.Width,
                                                     OuterPerimeter.Height
                                                 }));
            for (int x = OuterPerimeter.X; x < OuterPerimeter.X + OuterPerimeter.Width; x++)
                for (int y = OuterPerimeter.Y; y < OuterPerimeter.Y + OuterPerimeter.Height; y++)
                    if (y == OuterPerimeter.Y || y == OuterPerimeter.Y + OuterPerimeter.Height - 1 || x == OuterPerimeter.X || x == OuterPerimeter.X + OuterPerimeter.Width - 1)
                    {
                        map[x][y].Architecture = _wallType;
                        File.AppendAllText("map.txt", String.Format("Room {2}: ({0}, {1})\r\n", x, y, _name));
                    } else
                        map[x][y].Architecture = _level.BaseArchitecture;
        }

        public bool Place()
        {
            if (OuterPerimeter == null)
                return false;

            int attempts = 0;
            do
            {
                OuterPerimeter =
                    new Rectangle(
                        Math.Min(Game.Roll(2, (_levelDimensions.Width - OuterPerimeter.Width / 2) / 2),
                                 _levelDimensions.Width - 4),
                        Math.Min(Game.Roll(2, (_levelDimensions.Height - OuterPerimeter.Height / 2) / 2),
                                 _levelDimensions.Height - 4), 0, 0);
                attempts++;
                if (attempts == 10)
                {
                    // Screw random placement...
                    // Discard the room
                    return false;
                }
            } while (_rooms.Any(r => r.OuterPerimeter.IntersectsWith(OuterPerimeter)));
            return true;
        }

        public bool Resize()
        {
            if (OuterPerimeter == null)
                return false;
            int attempts = 0;
            RoomSize roomSizeCategory = RoomSize.Small;
            do
            {
                if (attempts > 0)
                    _level.RoomCountsBySize[(int)roomSizeCategory]--;
                int roomSize = Game.Roll(1, 30);

                int minSize = 4;
                int maxArea, maxX, maxY;
                int minArea = 16;
                int sizeX = 0, sizeY = 0;

                // Small room
                if (roomSize < 6)
                {
                    maxArea = 32;
                    sizeX = Game.Roll(1, maxArea / minSize, minSize);
                    sizeY = Game.Roll(1, maxArea / sizeX, minSize);
                    roomSizeCategory = RoomSize.Small;
                }
                // Medium room
                else if (roomSize < 27)
                {
                    maxArea = 64;
                    minArea = 46;
                    sizeX = Game.Roll(1, maxArea / minSize, 6);
                    sizeY = Game.Roll(1, maxArea / sizeX, Math.Max(minSize, minArea / sizeX));
                    roomSizeCategory = RoomSize.Medium;
                }
                // Big room
                else
                {
                    maxArea = 256;
                    minArea = 48;
                    sizeX = Game.Roll(1, maxArea / 10, 10);
                    sizeY = Game.Roll(2, maxArea / sizeX / 2, Math.Max(minSize, minArea / sizeX));
                    roomSizeCategory = RoomSize.Large;
                }
                // Update room counts
                _level.RoomCountsBySize[(int)roomSizeCategory]++;

                // Randomly swap X & Y
                if (Game.Roll(1, 2) == 1)
                {
                    int temp = sizeX;
                    sizeX = sizeY;
                    sizeY = sizeX;
                }
                // Create BoundingBox constrained to fit the level
                OuterPerimeter = new Rectangle(OuterPerimeter.X,
                                            OuterPerimeter.Y,
                                            Math.Min(sizeX, _levelDimensions.Width - OuterPerimeter.X),
                                            Math.Min(sizeY, _levelDimensions.Height - OuterPerimeter.Y));
                attempts++;

                if (attempts == 10)
                {
                    // Screw random placement...
                    // Discard the room 
                    return false;
                }
            } while (_rooms.Any(r => r.OuterPerimeter.IntersectsWith(OuterPerimeter)));
            bool intersects = _rooms.Any(r => r.OuterPerimeter.IntersectsWith(OuterPerimeter));
            Rectangle borderRectangle = OuterPerimeter;
            borderRectangle.Inflate(1, 1);
            //borderRectangle.Offset(-1, -1);
            var intersectedRoom = _rooms.Where(r => r.OuterPerimeter.IntersectsWith(borderRectangle)).FirstOrDefault();
            if (intersectedRoom != null)
            {
                Rectangle intersectedRect = borderRectangle;
                Rectangle newRect = OuterPerimeter;
                intersectedRect.Intersect(intersectedRoom.OuterPerimeter);
                // Move the smallest amount to get away
                if (intersectedRect.Width > intersectedRect.Height)
                    // Up or down?
                    newRect.Offset(0, borderRectangle.Y > intersectedRoom.OuterPerimeter.Y ? intersectedRect.Height : -intersectedRect.Height);
                else
                    // Left or right?
                    newRect.Offset(borderRectangle.X > intersectedRoom.OuterPerimeter.X ? intersectedRect.Width : -intersectedRect.Width, 0);
                if (_levelDimensions.Contains(newRect) && !_rooms.Any(r => r.OuterPerimeter.IntersectsWith(newRect)))
                    OuterPerimeter = newRect;
            }

            return true;
        }
    }
}
